<template>
  <div class="layout-container flex">
    <div class="flex-1 layout-main">
      <grid-layout
        v-model:layout="layout"
        :col-num="config.colNum"
        :row-height="config.rowHeight"
        :is-draggable="true"
        :is-resizable="true"
        :is-mirrored="false"
        :vertical-compact="true"
        :margin="config.margin"
        :use-css-transforms="false"
        ref="gridRef"
        @layout-updated="layoutUpdatedEvent"
      >
        <grid-item
          v-for="item in layout"
          :x="item.x"
          :y="item.y"
          :w="item.w"
          :h="item.h"
          :i="item.i"
          :key="item.i"
          :attr-key="item.i - 1"
          @click="(ev) => {}"
        >
          <i class="icon iconfont icon-delete" @click="remove(i)"></i>
          <div class="set">
            <i class="icon iconfont icon-edit"></i>
            <div class="box">
              <div class="line flex">
                <label>宽带：</label>
                <a-input
                  :value="item.w"
                  @blur="
                    (val) => adjustLayoutAutomatically('w', val, item.i - 1)
                  "
                ></a-input>
              </div>
              <div class="line flex">
                <label>高度：</label>
                <a-input
                  :value="item.h"
                  @blur="
                    (val) => adjustLayoutAutomatically('h', val, item.i - 1)
                  "
                ></a-input>
              </div>
            </div>
          </div>
        </grid-item>
      </grid-layout>
    </div>
    <div class="layout-box">
      <div class="layout-set">
        <AiForm :data="form.data" @change="changeLayout" />
        <a-button type="primary" class="ml-3" @click="submit">确定</a-button>
        <a-button @click="close" class="ml-1">取消</a-button>
      </div>
    </div>
  </div>
</template>
<script setup>
import Tool from "@/utils/tool";
const props = defineProps({
  lays: {
    type: Array,
    default: () => {
      return [];
    },
  },
  config: {
    type: Object,
    default: {
      colNum: 24,
      rowHeight: 10,
      margin: [0, 0],
    },
  },
});

const layoutCache = ref([]);
const am = {
  h: "y",
  w: "x",
};

const emit = defineEmits();

// 定义一个响应式的表单配置对象
const form = ref({
  data: [
    {
      // 定义一个输入框组件的配置
      type: "InputNumber",
      field: "num",
      allowClear: true,
      label: "个数",
      // 使用props.lays.length作为输入框的默认值
      value: props.lays.length,
      placeholder: "个数",
      labelWidth: "40px",
      style: {
        width: "100%",
      },
      // 定义输入框的校验规则
      rules: [
        {
          required: true,
          message: "请输入行数",
          trigger: "blur",
        },
      ],
    },
  ],
});

const remove = (index) => {
  layout.value.splice(index, 1);
};

/**
 * 调整布局函数
 * 当表单中的个数发生变化时调用此函数来更新布局
 * @param {Object} val - 包含新个数的对象，如果没有target属性则调用getGridLayout函数
 */
const changeLayout = (val) => {
  // 忽略由界面点击等事件引发的函数调用
  if (val.target) return;
  // 调用getGridLayout函数来获取新的布局
  getGridLayout(val.num);
};

const layout = ref([]);
const getGridLayout = (num) => {
  if (num === 0 || num === layout.value.length) return;
  layout.value = [];
  for (let i = 0; i < num; i++) {
    layout.value.push({
      i: i + 1,
      x: 0,
      y: 0,
      w: 24,
      h: 10,
    });
  }
  layoutCache.value = Tool.deepClone(layout.value);
};

/**
 * 计算网格布局的位置
 * 该函数根据传入的值和页面上的.layout-main元素的尺寸，计算出网格布局的列、行和网格项的位置
 * @param {Array} val - 包含每个网格项信息的数组，每个项包括x、y、w、h和i属性
 * @returns {Object} - 返回一个对象，包含列、行和网格项的位置信息
 */
const getPosition = (val) => {
  // 初始化x和y的起始位置
  let y = 0;
  let x = 0;
  // 获取.layout-main元素
  let dom = document.querySelector(".layout-main");

  // 如果未找到.layout-main元素，则输出错误信息并返回默认布局设置
  if (!dom) {
    console.error("Element with class .layout-main not found");
    return {
      col: `repeat(24, minmax(0, 1fr))`,
      row: `repeat(0, minmax(0, 1fr))`,
      grids: [],
    };
  }

  // 获取.layout-main元素的宽度和高度
  let dw = dom.clientWidth;
  let dh = dom.clientHeight;

  // 根据传入的网格项信息，计算每个网格项在网格布局中的位置
  const value = val.reduce((acc, a) => {
    // 更新最大的y和x值，以确定网格布局的行数和列数
    if (a.y > y) {
      y = a.y;
    }
    if (a.x > x) {
      x = a.x;
    }
    // 将网格项的位置信息添加到累积数组中
    acc.push({
      ...a,
      ax: `${a.x || 1} / ${a.w + a.x}`,
      ay: `${a.y || 1} / ${a.y + a.h}`,
      nm: "gm" + a.i,
    });
    return acc;
  }, []);

  // 返回网格布局的设置，包括列、行和网格项的位置信息
  return {
    col: `repeat(24, minmax(0, 1fr))`,
    row: `repeat(${Math.floor(dh / 10)}, minmax(0, 1fr))`,
    grids: value,
  };
};

let updatedVal = ref({});
const layoutUpdatedEvent = (val) => {
  updatedVal.value = val;
  console.log(val, "============val==============");
};

const close = () => {
  emit("close");
};

const getOffset = (el) => {
  // 获取某元素以浏览器左上角为原点的坐标
  let t = 0; // 获取该元素对应父容器的上边距
  let l = 0; // 对应父容器的上边距
  // 判断是否有父容器，如果存在则累加其边距
  while (el && el.tagName !== "BODY") {
    t += el.offsetTop;
    l += el.offsetLeft;
    el = el.offsetParent;
  }
  return {
    l: l,
    t: t,
  };
};

/**
 * 自动调整布局
 * 根据给定的类型（宽度或高度）和新值，自动调整布局中的相应属性。
 *
 * @param {string} dimension - 调整的维度，可以是 'w'（宽度）或 'h'（高度）
 * @param {Event} event - 触发事件的对象，通常是从输入框获取的新值
 * @param {number} targetIndex - 需要调整的布局项的索引
 */
const adjustLayoutAutomatically = (dimension, event, targetIndex) => {
  // 获取新值并转换为数字
  const newValue = Number(event.target.value);
  // 存储需要调整的布局项
  const changes = [];
  // 获取原始布局项
  const originalItem = layoutCache.value[targetIndex];
  console.log(event, "0000");

  // 遍历所有布局项
  layout.value.forEach((item, index) => {
    if (dimension === "h" && item.y === originalItem.h) {
      // 如果调整的是高度且 y 坐标相同，则计算新的高度
      changes.push({
        index,
        modifiedValue: Math.max(
          0,
          item[dimension] - (newValue - originalItem.h)
        ),
      });
    } else if (
      dimension === "w" &&
      item.x === originalItem[dimension] &&
      layout.value[index].y === item.y
    ) {
      // 如果调整的是宽度且 x 坐标和 y 坐标相同，则计算新的宽度
      changes.push({
        index,
        modifiedValue: Math.max(
          0,
          item[dimension] - (newValue - originalItem[dimension])
        ),
      });
    }
  });

  // 如果有需要调整的布局项，则进行调整
  if (changes.length > 0) {
    changes.forEach((change) => {
      layout.value[change.index][am[dimension]] = newValue;
      layout.value[change.index][dimension] = change.modifiedValue;
    });
  }

  // 更新目标布局项的值
  layout.value[targetIndex][dimension] = newValue;
  // 更新布局缓存
  layoutCache.value = [...layout.value];
  console.log(layoutCache.value, "99999");
};

watch(
  () => props.lays,
  (val) => {
    const maps = val.map((a, i) => {
      return {
        ...a,
        i: i + 1,
        x: a.x,
        y: a.y,
        w: a.w,
        h: a.h,
      };
    });
    console.log(val, "===props.lays===");
    layout.value = maps;
    layoutCache.value = Tool.deepClone(layout.value);
  },
  {
    immediate: true,
  }
);

const submit = () => {
  const pos = getPosition(updatedVal.value);
  emit("confirm", pos);
};
</script>
<style scoped lang="scss">
.layout-container {
  position: fixed;
  width: 100%;
  height: 100%;
  left: 0;
  top: 0;
  background: rgba(0, 0, 0, 0.4);
  z-index: 100;
}

.vue-grid-layout {
  background: #eee;
  height: 100%;
}

.vue-grid-item:not(.vue-grid-placeholder) {
  background: #ccc;
  border: 1px solid black;
}

.vue-grid-item .resizing {
  opacity: 0.9;
}

.vue-grid-item .static {
  background: #cce;
}

.vue-grid-item .text {
  font-size: 24px;
  text-align: center;
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  margin: auto;
  height: 100%;
  width: 100%;
}

.vue-grid-item .no-drag {
  height: 100%;
  width: 100%;
}

.vue-grid-item .minMax {
  font-size: 12px;
}

.vue-grid-item .add {
  cursor: pointer;
}

.vue-draggable-handle {
  position: absolute;
  width: 20px;
  height: 20px;
  top: 0;
  left: 0;
  background: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='10'><circle cx='5' cy='5' r='5' fill='#999999'/></svg>")
    no-repeat;
  background-position: bottom right;
  padding: 0 8px 8px 0;
  background-repeat: no-repeat;
  background-origin: content-box;
  box-sizing: border-box;
  cursor: pointer;
}

.layoutJSON {
  background: #ddd;
  border: 1px solid black;
  margin-top: 10px;
  padding: 10px;
}

.layoutJSON {
  background: #ddd;
  border: 1px solid black;
  margin-top: 10px;
  padding: 10px;
}

.columns {
  -moz-columns: 120px;
  -webkit-columns: 120px;
  columns: 120px;
}

.layout-box {
  width: 300px;
  height: 100%;
  background-color: #fff;
  .icon-Banner {
    cursor: pointer;
    color: #2c3e50;
  }
  .layout-set {
    background: rgba(255, 255, 255);
    z-index: 100;
    right: 0;
    padding: 30px 20px 10px;
  }
  .ml-3 {
    margin-left: 48px;
  }
  .ml-1 {
    margin-left: 10px;
  }
}
.flex-1 {
  flex: 1;
  background-color: #fff;
}

.icon-delete {
  position: absolute;
  right: 10px;
  top: 30px;
  cursor: pointer;
}
.set {
  position: absolute;
  right: 10px;
  top: 3px;
  z-index: 100;
  &:hover .box {
    visibility: visible;
    z-index: 100;
  }
  .icon {
    font-size: 20px;
    margin-left: 10px;
    cursor: pointer;
  }
  .box {
    position: absolute;
    right: 35px;
    top: 0;
    width: 300px;
    background: rgba(255, 255, 255, 0.6);
    padding: 15px;
    visibility: hidden;
    .line {
      display: flex;
      align-items: center;
      margin-bottom: 10px;
      label {
        width: 80px;
        font-size: 12px;
      }
    }
  }
}
</style>
